@@ -21,6 +21,7 @@ class Agent < ActiveRecord::Base |
||
21 | 21 |
attr_accessible :options, :memory, :name, :type, :schedule, :source_ids, :keep_events_for |
22 | 22 |
|
23 | 23 |
validates_presence_of :name, :user |
24 |
+ validates_inclusion_of :keep_events_for, :in => EVENT_RETENTION_SCHEDULES.map(&:last) |
|
24 | 25 |
validate :sources_are_owned |
25 | 26 |
validate :validate_schedule |
26 | 27 |
|
@@ -29,6 +30,7 @@ class Agent < ActiveRecord::Base |
||
29 | 30 |
before_validation :unschedule_if_cannot_schedule |
30 | 31 |
before_save :unschedule_if_cannot_schedule |
31 | 32 |
before_create :set_last_checked_event_id |
33 |
+ after_save :possibly_update_event_expirations |
|
32 | 34 |
|
33 | 35 |
belongs_to :user, :inverse_of => :agents |
34 | 36 |
has_many :events, :dependent => :delete_all, :inverse_of => :agent, :order => "events.id desc" |
@@ -175,6 +177,18 @@ class Agent < ActiveRecord::Base |
||
175 | 177 |
end |
176 | 178 |
end |
177 | 179 |
|
180 |
+ def possibly_update_event_expirations |
|
181 |
+ update_event_expirations! if keep_events_for_changed? |
|
182 |
+ end |
|
183 |
+ |
|
184 |
+ def update_event_expirations! |
|
185 |
+ if keep_events_for == 0 |
|
186 |
+ events.update_all :expires_at => nil |
|
187 |
+ else |
|
188 |
+ events.update_all "expires_at = DATE_ADD(`created_at`, INTERVAL #{keep_events_for.to_i} DAY)" |
|
189 |
+ end |
|
190 |
+ end |
|
191 |
+ |
|
178 | 192 |
# Class Methods |
179 | 193 |
class << self |
180 | 194 |
def cannot_be_scheduled! |
@@ -249,7 +249,7 @@ describe Agent do |
||
249 | 249 |
agent.should have(0).errors_on(:base) |
250 | 250 |
end |
251 | 251 |
|
252 |
- it "symbolizes options before validating" do |
|
252 |
+ it "makes options symbol-indifferent before validating" do |
|
253 | 253 |
agent = Agents::SomethingSource.new(:name => "something") |
254 | 254 |
agent.user = users(:bob) |
255 | 255 |
agent.options["bad"] = true |
@@ -258,7 +258,7 @@ describe Agent do |
||
258 | 258 |
agent.should have(0).errors_on(:base) |
259 | 259 |
end |
260 | 260 |
|
261 |
- it "symbolizes memory before validating" do |
|
261 |
+ it "makes memory symbol-indifferent before validating" do |
|
262 | 262 |
agent = Agents::SomethingSource.new(:name => "something") |
263 | 263 |
agent.user = users(:bob) |
264 | 264 |
agent.memory["bad"] = :hello |
@@ -276,7 +276,85 @@ describe Agent do |
||
276 | 276 |
agent.user = users(:jane) |
277 | 277 |
agent.should have(0).errors_on(:sources) |
278 | 278 |
end |
279 |
+ |
|
280 |
+ it "validates keep_events_for" do |
|
281 |
+ agent = Agents::SomethingSource.new(:name => "something") |
|
282 |
+ agent.user = users(:bob) |
|
283 |
+ agent.should be_valid |
|
284 |
+ agent.keep_events_for = nil |
|
285 |
+ agent.should have(1).errors_on(:keep_events_for) |
|
286 |
+ agent.keep_events_for = 1000 |
|
287 |
+ agent.should have(1).errors_on(:keep_events_for) |
|
288 |
+ agent.keep_events_for = "" |
|
289 |
+ agent.should have(1).errors_on(:keep_events_for) |
|
290 |
+ agent.keep_events_for = 5 |
|
291 |
+ agent.should be_valid |
|
292 |
+ agent.keep_events_for = 0 |
|
293 |
+ agent.should be_valid |
|
294 |
+ agent.keep_events_for = 365 |
|
295 |
+ agent.should be_valid |
|
296 |
+ |
|
297 |
+ # Rails seems to call to_i on the input. This guards against future changes to that behavior. |
|
298 |
+ agent.keep_events_for = "drop table;" |
|
299 |
+ agent.keep_events_for.should == 0 |
|
300 |
+ end |
|
301 |
+ end |
|
302 |
+ |
|
303 |
+ describe "cleaning up now-expired events" do |
|
304 |
+ before do |
|
305 |
+ @agent = Agents::SomethingSource.new(:name => "something") |
|
306 |
+ @agent.keep_events_for = 5 |
|
307 |
+ @agent.user = users(:bob) |
|
308 |
+ @agent.save! |
|
309 |
+ @event = @agent.create_event :payload => { "hello" => "world" } |
|
310 |
+ @event.expires_at.to_i.should be_within(2).of(5.days.from_now.to_i) |
|
311 |
+ end |
|
312 |
+ |
|
313 |
+ describe "when keep_events_for has not changed" do |
|
314 |
+ it "does nothing" do |
|
315 |
+ mock(@agent).update_event_expirations!.times(0) |
|
316 |
+ |
|
317 |
+ @agent.options[:foo] = "bar1" |
|
318 |
+ @agent.save! |
|
319 |
+ |
|
320 |
+ @agent.options[:foo] = "bar1" |
|
321 |
+ @agent.keep_events_for = 5 |
|
322 |
+ @agent.save! |
|
323 |
+ end |
|
324 |
+ end |
|
325 |
+ |
|
326 |
+ describe "when keep_events_for is changed" do |
|
327 |
+ it "updates events' expires_at" do |
|
328 |
+ lambda { |
|
329 |
+ @agent.options[:foo] = "bar1" |
|
330 |
+ @agent.keep_events_for = 3 |
|
331 |
+ @agent.save! |
|
332 |
+ }.should change { @event.reload.expires_at } |
|
333 |
+ @event.expires_at.to_i.should be_within(2).of(3.days.from_now.to_i) |
|
334 |
+ end |
|
335 |
+ |
|
336 |
+ it "updates events relative to their created_at" do |
|
337 |
+ @event.update_attribute :created_at, 2.days.ago |
|
338 |
+ @event.reload.created_at.to_i.should be_within(2).of(2.days.ago.to_i) |
|
339 |
+ |
|
340 |
+ lambda { |
|
341 |
+ @agent.options[:foo] = "bar2" |
|
342 |
+ @agent.keep_events_for = 3 |
|
343 |
+ @agent.save! |
|
344 |
+ }.should change { @event.reload.expires_at } |
|
345 |
+ @event.expires_at.to_i.should be_within(2).of(1.days.from_now.to_i) |
|
346 |
+ end |
|
347 |
+ |
|
348 |
+ it "nulls out expires_at when keep_events_for is set to 0" do |
|
349 |
+ lambda { |
|
350 |
+ @agent.options[:foo] = "bar" |
|
351 |
+ @agent.keep_events_for = 0 |
|
352 |
+ @agent.save! |
|
353 |
+ }.should change { @event.reload.expires_at }.to(nil) |
|
354 |
+ end |
|
355 |
+ end |
|
279 | 356 |
end |
357 |
+ |
|
280 | 358 |
end |
281 | 359 |
|
282 | 360 |
describe "scopes" do |